package org.NooLab.itexx.app.gui;

import java.awt.*;
import java.awt.image.*;
import javax.swing.*;

/*
 *  Support custom painting on a panel in the form of
 *
 *  a) images - that can be scaled, tiled or painted at original size
 *  b) non solid painting - that can be done by using a Paint object
 *
 *  Also, any component added directly to this panel will be made
 *  non-opaque so that the custom painting can show through.
 */
public class BackgroundPanel extends JPanel {
	public static final int SCALED = 0;
	public static final int TILED = 1;
	public static final int ACTUAL = 2;

	private Paint painter;
	private Image image=null;
	private int style = SCALED;
	private float alignmentX = 0.5f;
	private float alignmentY = 0.5f;
	private boolean isTransparentAdd = true;

	/*
	 * Set image as the background with the SCALED style
	 */
	public BackgroundPanel(Image image) {
		this(image, SCALED);
	}

	/*
	 * Set image as the background with the specified style
	 */
	public BackgroundPanel(Image image, int style) {
		setImage(image);
		setStyle(style);
		setLayout(new BorderLayout());
	}

	/*
	 * Set image as the background with the specified style and alignment
	 */
	public BackgroundPanel(Image image, int style, float alignmentX, float alignmentY) {
		setImage(image);
		setStyle(style);
		setImageAlignmentX(alignmentX);
		setImageAlignmentY(alignmentY);
		setLayout(new BorderLayout());
	}


	
	public BackgroundPanel() {
		
		setLayout(new BorderLayout());
	}

	/*
	 * Use the Paint interface to paint a background
	 */
	public BackgroundPanel(Paint painter) {
		setPaint(painter);
		setLayout(new BorderLayout());
	}

	/*
	 * Set the image used as the background
	 */
	public void setImage(Image image) {
		this.image = image;
		repaint();
	}

	/*
	 * Set the style used to paint the background image
	 */
	public void setStyle(int style) {
		this.style = style;
		repaint();
	}

	/*
	 * Set the Paint object used to paint the background
	 */
	public void setPaint(Paint painter) {
		this.painter = painter;
		repaint();
	}

	/*
	 * Specify the horizontal alignment of the image when using ACTUAL style
	 */
	public void setImageAlignmentX(float alignmentX) {
		this.alignmentX = alignmentX > 1.0f ? 1.0f : alignmentX < 0.0f ? 0.0f : alignmentX;
		repaint();
	}

	/*
	 * Specify the horizontal alignment of the image when using ACTUAL style
	 */
	public void setImageAlignmentY(float alignmentY) {
		this.alignmentY = alignmentY > 1.0f ? 1.0f : alignmentY < 0.0f ? 0.0f : alignmentY;
		repaint();
	}

	/*
	 * Override method so we can make the component transparent
	 */
	public void add(JComponent component) {
		add(component, null);
	}

	/*
	 * Override to provide a preferred size equal to the image size
	 */
	@Override
	public Dimension getPreferredSize() {
		if (image == null)
			return super.getPreferredSize();
		else
			return new Dimension(image.getWidth(null), image.getHeight(null));
	}

	/*
	 * Override method so we can make the component transparent
	 */
	public void add(JComponent component, Object constraints) {
		if (isTransparentAdd) {
			makeComponentTransparent(component);
		}

		super.add(component, constraints);
	}

	/*
	 * Controls whether components added to this panel should automatically be
	 * made transparent. That is, setOpaque(false) will be invoked. The default
	 * is set to true.
	 */
	public void setTransparentAdd(boolean isTransparentAdd) {
		this.isTransparentAdd = isTransparentAdd;
	}

	/*
	 * Try to make the component transparent. For components that use renderers,
	 * like JTable, you will also need to change the renderer to be transparent.
	 * An easy way to do this it to set the background of the table to a Color
	 * using an alpha value of 0.
	 */
	private void makeComponentTransparent(JComponent component) {
		component.setOpaque(false);

		if (component instanceof JScrollPane) {
			JScrollPane scrollPane = (JScrollPane) component;
			JViewport viewport = scrollPane.getViewport();
			viewport.setOpaque(false);
			Component c = viewport.getView();

			if (c instanceof JComponent) {
				((JComponent) c).setOpaque(false);
			}
		}
	}

	/*
	 * Add custom painting
	 */
	@Override
	protected void paintComponent(Graphics g) {
		

		// Invoke the painter for the background

		if (painter != null) {
			Dimension d = getSize();
			Graphics2D g2 = (Graphics2D) g;
			g2.setPaint(painter);
			g2.fill(new Rectangle(0, 0, d.width, d.height));
		}

		// Draw the image

		if (image == null) return;

		if (image != null) {
			switch (style) {
				case SCALED:
					drawScaled(g);
					break;

				case TILED:
					drawTiled(g);
					break;

				case ACTUAL:
					drawActual(g);
					break;

				default:
					drawScaled(g);
			}
		}
		
		super.paintComponent(g);
	}

	/*
	 * Custom painting code for drawing a SCALED image as the background
	 */
	private void drawScaled(Graphics g) {
		Dimension d = getSize();
		if (image!=null){
			g.drawImage(image, 0, 0, d.width, d.height, null);
		}
	}

	/*
	 * Custom painting code for drawing TILED images as the background
	 */
	private void drawTiled(Graphics g) {
		Dimension d = getSize();
		int width = image.getWidth(null);
		int height = image.getHeight(null);

		if (image!=null){
			for (int x = 0; x < d.width; x += width) {
				for (int y = 0; y < d.height; y += height) {
					g.drawImage(image, x, y, null, null);
				}
			}
		}
	}

	/*
	 * Custom painting code for drawing the ACTUAL image as the background. The
	 * image is positioned in the panel based on the horizontal and vertical
	 * alignments specified.
	 */
	private void drawActual(Graphics g) {
		Dimension d = getSize();
		Insets insets = getInsets();
		int width = d.width - insets.left - insets.right;
		int height = d.height - insets.top - insets.left;
		float x = (width - image.getWidth(null)) * alignmentX;
		float y = (height - image.getHeight(null)) * alignmentY;
		if (image!=null){
			g.drawImage(image, (int) x + insets.left, (int) y + insets.top, this);
		}
	}
}
